#include "example.h"

//
//SDK中默认的SPI驱动，是封装给flash用的，不能像ST的通用SPI一样给普通外设使用。
//如果要给其他外设使用，则设备必须满足一定的时序（参考datasheet中的详细描述）。
//时序限制：
//1. SPI交互时第一段只能是tx（不能是rx）；
//2. 收和发不能同时进行（只能是发完再收）；
//3. rx后边不能再有tx（rx位于一次交互的最后一段）；
//
//所以，这个C中提供2个函数：
//1.Send：单纯发送数据，字节数不限制；
//2.SendAndRecv：在一个片选周期内，发送一段数据，再接收一段数据； 
//               其中发送长度最长4byte，接收长度不限。
//              （如果发送长度要更长，请自行扩展。）
//
//使用说明：
//datasheet中引入PHASE的概念：TX、RX、DummyTx。每个对应一种动作。
//在一次完整的SPI交互动作中，可以最多配置8个动作。配置后，这8个动作会在一次交互中按顺序全部执行。
//每个动作之间是相互独立的。
//比如，可以配置 TX-dummyTX-TX-TX-RX 这样的5次连续动作。配置后调用SPI_Start，则5个动作顺序执行。
//（以下样例函数SPI_SendAndRecv_Short中，配置了Tx-RX的两个动作。）
//如果只配置一次动作，只能是tx，不能是rx。
//
//DummyTx是比较特殊的一种tx。配置DummyTx时，不用配置数据，因为DummyTx会自动发送空数据。
//DummyTx配置的len，是以byte为单位的。
//
//当收和发在4byte内，可一次配置；如果超出4byte，最好用dma；
//（如果发送超过4byte，可以配在一个dma里，也可以配置多个连续的tx（总数不能超过4*8）。
//如果收的超过4byte，就用dma。
//

//发送字节长度不大于4byte
int SPI_Send_Short(SPI_TypeDef *spi, uint8_t *txBuff, int txLen)
{
  if (txLen > 4 ) return 0; //should use DMA.

  uint32_t txData = 0;
  if (txLen <= 4) txData = txBuff[0] + (txBuff[1] << 8) + (txBuff[2] << 16) + (txBuff[3] << 24);

  // Command phase is always the first phase and tx 1 byte in single mode
  SPI_SetPhaseCtrl(spi, SPI_PHASE_0, SPI_PHASE_ACTION_TX, SPI_PHASE_MODE_SINGLE, txLen); //配置第一个PHASE为 TX
  SPI_SetPhaseData(spi, SPI_PHASE_0, txData); //配置要发送的数据

  SPI_Start(spi, SPI_CTRL_PHASE_CNT1, SPI_CTRL_DMA_OFF, SPI_INTERRUPT_OFF); //启动SPI（有一个PHASE）
  SPI_WaitForDone(spi);
  return 1;
}
//发送长度大于4byte时
int SPI_Send_Long(SPI_TypeDef *spi, uint8_t *txBuff, int txLen)
{
  DMAC_ChannelNumTypeDef tx_spi_dmac_channel = DMAC_CHANNEL7;

  // SYS_EnableAHBClock(AHB_MASK_DMAC0);
  // DMAC_Init();

  DMAC_DisableSyncRequest(SPI_TX_DMA_REQ(spi));
  DMAC_DisableSyncRequest(SPI_RX_DMA_REQ(spi));
  DMAC_EnableChannel(tx_spi_dmac_channel);

  uint32_t txData = 0;
  txData = txBuff[0] + (txBuff[1] << 8) + (txBuff[2] << 16) + (txBuff[3] << 24);

  SPI_SetPhaseCtrl(spi, SPI_PHASE_0, SPI_PHASE_ACTION_TX, SPI_PHASE_MODE_SINGLE, 4); //配置第一个PHASE为 TX
  SPI_SetPhaseData(spi, SPI_PHASE_0, txData); //配置要发送的数据
  // Command phase is always the first phase and tx 1 byte in single mode
  SPI_SetPhaseCtrl(spi, SPI_PHASE_1, SPI_PHASE_ACTION_TX, SPI_PHASE_MODE_SINGLE, txLen-4); //配置第二个PHASE为 DMA TX
  //配置要发送的数据(DMA方式)
  DMAC_Config(tx_spi_dmac_channel, (uint32_t)txBuff+4, (uint32_t)&spi->PHASE_DATA[SPI_PHASE_1],
              DMAC_ADDR_INCR_ON, DMAC_ADDR_INCR_OFF, DMAC_WIDTH_32_BIT, DMAC_WIDTH_32_BIT,
              DMAC_BURST_1, DMAC_BURST_1, 0, DMAC_MEM_TO_PERIPHERAL_PERIPHERAL_CTRL,
              0, SPI_TX_DMA_REQ(spi));

  SPI_Start(spi, SPI_CTRL_PHASE_CNT2, SPI_CTRL_DMA_ON, SPI_INTERRUPT_OFF); //启动SPI（有两个PHASE）
  SPI_WaitForDone(spi);

  DMAC_DisableChannel(tx_spi_dmac_channel);

  return 1;
}
//spi发送
int SPI_Send(SPI_TypeDef *spi, uint8_t *txBuff, int txLen)
{
    if (txLen <= 4)
    {
      return SPI_Send_Short(spi, txBuff, txLen);
    }
    else
    {
      return SPI_Send_Long(spi, txBuff, txLen);
    }
}


//当收的长度不大于4byte，可以直接来收
int SPI_SendAndRecv_Short(SPI_TypeDef *spi, uint8_t *txBuff, int txLen, uint8_t *rxBuff, int rxLen)
{
  if (txLen > 4 || rxLen > 4) return 0; //should use DMA.

  uint32_t txData = 0, rxData = 0;
  if (txLen <= 4) txData = txBuff[0] + (txBuff[1] << 8) + (txBuff[2] << 16) + (txBuff[3] << 24);

  // Command phase is always the first phase and tx 1 byte in single mode
  SPI_SetPhaseCtrl(spi, SPI_PHASE_0, SPI_PHASE_ACTION_TX, SPI_PHASE_MODE_SINGLE, txLen); //配置第一个PHASE为 TX
  SPI_SetPhaseData(spi, SPI_PHASE_0, txData); //配置要发送的数据

  SPI_SetPhaseCtrl(spi, SPI_PHASE_1, SPI_PHASE_ACTION_RX, SPI_PHASE_MODE_SINGLE, rxLen); //配置第二个PHASE为 RX
  
  SPI_Start(spi, SPI_CTRL_PHASE_CNT2, SPI_CTRL_DMA_OFF, SPI_INTERRUPT_OFF); //启动SPI（有两个PHASE）
  SPI_WaitForDone(spi);

  rxData = spi->PHASE_DATA[SPI_PHASE_1]; //拿RX对应的数据
  rxBuff[0] = rxData & 0xFF;
  rxBuff[1] = (rxData >> 8) & 0xFF;
  rxBuff[2] = (rxData >> 16) & 0xFF;
  rxBuff[3] = (rxData >> 24) & 0xFF;
  return 1;
}
//当收的长度大于4byte，用DMA来收
int SPI_SendAndRecv_Long(SPI_TypeDef *spi, uint8_t *txBuff, int txLen, uint8_t *rxBuff, int rxLen)
{
  if (txLen > 4) 
  {
    printf("SPI tx data is too long. You should make new FUNCTION for it!\n\n");
    return 0; //should use multi-tx.
  }
  
  DMAC_ChannelNumTypeDef rx_spi_dmac_channel = DMAC_CHANNEL7;

  // SYS_EnableAHBClock(AHB_MASK_DMAC0);
  // DMAC_Init();

  DMAC_DisableSyncRequest(SPI_TX_DMA_REQ(spi));
  DMAC_DisableSyncRequest(SPI_RX_DMA_REQ(spi));
  DMAC_EnableChannel(rx_spi_dmac_channel);

  uint32_t txData = 0;
  txData = txBuff[0] + (txBuff[1] << 8) + (txBuff[2] << 16) + (txBuff[3] << 24);

  // Command phase is always the first phase and tx 1 byte in single mode
  SPI_SetPhaseCtrl(spi, SPI_PHASE_0, SPI_PHASE_ACTION_TX, SPI_PHASE_MODE_SINGLE, txLen); //配置第一个PHASE为 TX
  SPI_SetPhaseData(spi, SPI_PHASE_0, txData); //配置要发送的数据

  SPI_SetPhaseCtrl(spi, SPI_PHASE_1, SPI_PHASE_ACTION_RX, SPI_PHASE_MODE_SINGLE, rxLen); //配置第二个PHASE为 DMA RX
  DMAC_Config(rx_spi_dmac_channel, (uint32_t)&spi->PHASE_DATA[SPI_PHASE_1], (uint32_t)rxBuff,
              DMAC_ADDR_INCR_OFF, DMAC_ADDR_INCR_ON, DMAC_WIDTH_32_BIT, DMAC_WIDTH_32_BIT,
              DMAC_BURST_1, DMAC_BURST_1, rxLen, DMAC_PERIPHERAL_TO_MEM_PERIPHERAL_CTRL,
              SPI_RX_DMA_REQ(spi), 0);
  
  SPI_Start(spi, SPI_CTRL_PHASE_CNT2, SPI_CTRL_DMA_ON, SPI_INTERRUPT_OFF); //启动SPI（有两个PHASE）
  SPI_WaitForDone(spi);

  DMAC_DisableChannel(rx_spi_dmac_channel);

  return 1;
}

//SPI一发一收
int SPI_SendAndRecv(SPI_TypeDef *spi, uint8_t *txBuff, int txLen, uint8_t *rxBuff, int rxLen)
{
    if (txLen <= 4 && rxLen <= 4)
    {
      return SPI_SendAndRecv_Short(spi, txBuff, txLen, rxBuff, rxLen);
    }
    else if (txLen <= 4 && rxLen > 4)
    {
      return SPI_SendAndRecv_Long(spi, txBuff, txLen, rxBuff, rxLen);
    }
    else
    {
      printf("You should make new FUNCTION for it!\n\n");
      return 0; //should use multi-tx when txLen <= 28.
    }
}

int TestSpiComm()
{
  //用SPI1来测试
  //VE中必须定义SPI1的4个引脚：SPI1_SCK、SPI1_SI_IO0、SPI1_SO_IO1、SPI1_CSN。 

  PERIPHERAL_ENABLE_ALL(SPI, 1);
  SPI_TypeDef *spi = SPIx(1);

  uint32_t pclk_freq = SYS_GetPclkFreq(); //如果VE里配置SYSCLK是100，则这里获取到的是100M。
  SPI_SclkDivTypeDef spi_sclk_div = pclk_freq > 240 ? SPI_CTRL_SCLK_DIV16 : pclk_freq > 120 ? SPI_CTRL_SCLK_DIV8 : SPI_CTRL_SCLK_DIV4;
  SPI_Init(spi, spi_sclk_div); //这里分频多少，是从SYSCLK基础上分频的。如果SYSCLK是100M，则这里16分频后SPI就是6.25M。

  uint8_t rxBuff[12];
  uint8_t txBuff[8] = {0xAA, 0x11, 0xAA, 0x12, 0xAA, 0x13, 0xAA, 0x14};
  SPI_Send(spi, txBuff, 4);
  //SPI_SendAndRecv(spi, txBuff, 4, rxBuff, 8);
  printf("SPI1 test recv:0x%02x%02x%02x%02x!\n\n", rxBuff[0], rxBuff[1], rxBuff[2], rxBuff[3]);

  return 1;
}
